#ifndef ELS_LANG_CN
    #ifndef ELS_LANG_EN
        #error "You defined none keyword patterns at the same time"
    #endif
#endif
#ifndef ELS_LANG_EN
    #ifndef ELS_LANG_CN
        #error "You defined none keyword patterns at the same time"
    #endif
#endif

#ifndef els_limits_h
#define els_limits_h

#include <limits.h>
#include <stddef.h>
#ifndef BITS_INT
#if INT_MAX - 20 < 32760
#define BITS_INT 16
#else
#if INT_MAX > 2147483640L
#define BITS_INT 32
#else
#error "you must define BITS_INT with number of bits in an integer"
#endif
#endif
#endif

#define ELS_NUM_TYPE double
typedef ELS_NUM_TYPE Number;

#define NUMBER_FMT "%.16g"
#define els_number2str(s, n) sprintf((s), NUMBER_FMT, (n))
#define els_str2number(s, p) strtod((s), (p))

typedef unsigned long lint32;

#define MAX_SIZET ((size_t)(~(size_t)0) - 2)

#define MAX_INT (INT_MAX - 2)
#define IntPoint(p) (((unsigned long)(p)) >> 3)

#define MINPOWER2 4
#define DEFAULT_STACK_SIZE 1024

union L_Umaxalign
{
    double d;
    char *s;
    long l;
};
typedef unsigned long Instruction;

#define SIZE_INSTRUCTION 32
#define SIZE_B 9
#define SIZE_OP 6
#define SIZE_U (SIZE_INSTRUCTION - SIZE_OP)
#define POS_U SIZE_OP
#define POS_B SIZE_OP
#define SIZE_A (SIZE_INSTRUCTION - (SIZE_OP + SIZE_B))
#define POS_A (SIZE_OP + SIZE_B)

#if SIZE_U < BITS_INT - 1
#define MAXARG_U ((1 << SIZE_U) - 1)
#define MAXARG_S (MAXARG_U >> 1) 
#else
#define MAXARG_U MAX_INT
#define MAXARG_S MAX_INT
#endif

#if SIZE_A < BITS_INT - 1
#define MAXARG_A ((1 << SIZE_A) - 1)
#else
#define MAXARG_A MAX_INT
#endif

#if SIZE_B < BITS_INT - 1
#define MAXARG_B ((1 << SIZE_B) - 1)
#else
#define MAXARG_B MAX_INT
#endif

#define MAXSTACK 250
#if MAXSTACK > MAXARG_B
#undef MAXSTACK
#define MAXSTACK MAXARG_B
#endif

#define MAXLOCALS 200
#if MAXLOCALS >= MAXSTACK
#undef MAXLOCALS
#define MAXLOCALS (MAXSTACK - 1)
#endif

#ifndef MAXUPVALUES
#define MAXUPVALUES 32
#endif
#if MAXUPVALUES > MAXARG_B
#undef MAXUPVALUES
#define MAXUPVALUES MAXARG_B
#endif

#ifndef MAXVARSLH
#define MAXVARSLH 100
#endif
#if MAXVARSLH >= MULT_RET
#undef MAXVARSLH
#define MAXVARSLH (MULT_RET - 1)
#endif
#ifndef MAXPARAMS
#define MAXPARAMS 100
#endif
#if MAXPARAMS >= MAXLOCALS
#undef MAXPARAMS
#define MAXPARAMS (MAXLOCALS - 1)
#endif
#define LFIELDS_PER_FLUSH 64
#if LFIELDS_PER_FLUSH > (MAXSTACK / 4)
#undef LFIELDS_PER_FLUSH
#define LFIELDS_PER_FLUSH (MAXSTACK / 4)
#endif
#define RFIELDS_PER_FLUSH (LFIELDS_PER_FLUSH / 2)
#define LOOKBACKNUMS 20

#endif



#ifndef els_h
#define els_h



#include <stddef.h>
#define ELS_API		extern

#define ELS_NOREF	(-2)
#define ELS_REFNULL	(-1)
#define ELS_REFREGISTRY	0
#define ELS_ANYTAG	(-1)
#define ELS_NOTAG	(-2)

#define ELS_MULTRET	(-1)
#define ELS_MINSTACK	20

#define ELS_ERRRUN	1
#define ELS_ERRFILE	2
#define ELS_ERRSYNTAX	3
#define ELS_ERRMEM	4
#define ELS_ERRERR	5

#define TSPACK ((int)sizeof(int))
typedef struct els_VmObj els_VmObj;
typedef int (*els_CFunction) (els_VmObj *L);


#define ELS_TYPE_USERDATA	0
#define ELS_TYPE_NULL	    1
#define ELS_TYPE_NUMBER	    2
#define ELS_TYPE_STRING	    3
#define ELS_TYPE_UNIT	    4
#define ELS_TYPE_FUNCTION	5

typedef union
{
    struct TString *ts;
    struct ElsCfunc *cl;
    struct Hash *a;
    struct CallInfo *i;
    double n;
} Value;
typedef struct els_StackObj
{
    int ttype;
    Value value;
} StackObj;

typedef struct TString
{
    union
    {
        struct
        {
            unsigned long hash;
            int constindex;
        } s;
        struct
        {
            int tag;
            void *value;
        } d;
    } u;
    size_t len;
    struct TString *nexthash;
    int marked;
    char str[TSPACK];
} TString;
typedef struct ElsCfunc
{
    union
    {
        els_CFunction c;
        struct els_ir_code *l;
    } f;
    struct ElsCfunc *next;
    struct ElsCfunc *mark;
    short isC;
    short nupvalues;
    StackObj upvalue[1];
} ElsCfunc;
typedef struct Node
{
    StackObj key;
    StackObj val;
    struct Node *next;
} Node;
typedef struct Hash
{
    Node *node;
    int htag;
    int size;
    Node *firstfree;
    struct Hash *next;
    struct Hash *mark;
} Hash;
typedef struct CallInfo
{
    struct ElsCfunc *func;
    const Instruction **pc;
    int lastpc;
    int line;
    int refi;
} CallInfo;




typedef struct els_ir_code
{
    Number *knum;
    int nknum;
    struct TString **kstr;
    int nkstr;
    struct els_ir_code **kcodeir;
    int nkcodeir;
    Instruction *code;
    int ncode;
    short numparams;
    short is_vararg;
    short maxstacksize;
    short marked;
    struct els_ir_code *next;
    int *lineinfo;
    int nlineinfo;
    int nlocvars;
    struct LocVar *locvars;
    int lineDefined;
    TString *source;
} els_ir_code;

typedef struct LocVar
{
    TString *varname;
    int startpc;
    int endpc;
} LocVar;




/*VM api*/
ELS_API els_VmObj*          els_createvm (int stacksize);
ELS_API void                els_closevm (els_VmObj *L);
ELS_API void                els_error (els_VmObj *L, const char *s);
#define                     els_vmstop(l)               (els_Heap_breakrun(l,ELS_ERRRUN))

/*exec api*/
ELS_API int   els_call (els_VmObj *L, int nargs, int nresults);
ELS_API int   els_dofile (els_VmObj *L, const char *filename);
ELS_API int   els_dostring (els_VmObj *L, const char *str);
ELS_API int   els_dobuffer (els_VmObj *L, const char *buff, size_t size, const char *name);


/*api type is*/
ELS_API int                 els_type (els_VmObj *L, int index);
#define                     els_isnum(L,n)	    (els_type(L,n) == ELS_TYPE_NUMBER)
#define                     els_isstr(L,n)	    (els_type(L,n) == ELS_TYPE_STRING)
#define                     els_isfunc(L,n)	    (els_type(L,n) == ELS_TYPE_FUNCTION)
#define                     els_isunit(L,n)	    (els_type(L,n) == ELS_TYPE_UNIT)
#define                     els_isnull(L,n)		(els_type(L,n) == ELS_TYPE_NULL)

/*api stack get*/
ELS_API StackObj*           els_getstackobj (els_VmObj *L, int index) ;
ELS_API double              els_getnum (els_VmObj *L, int index);
ELS_API const char*         els_getstr (els_VmObj *L, int index);
ELS_API els_CFunction       els_getfunc (els_VmObj *L, int index);
ELS_API void                els_getvmvalue (els_VmObj *L, const char *name);

/*apt stack push*/
ELS_API void  els_pushnull (els_VmObj *L);
ELS_API void  els_pushnum (els_VmObj *L, double n);
ELS_API void  els_pushstr (els_VmObj *L, const char *s);
ELS_API void  els_pushvmvalue (els_VmObj *L, const char *name);

/*api Cfunction*/
#define els_register(L,n,f)	(els_pushcfunciotn(L, f, 0), els_pushvmvalue(L, n))
void els_pushcfunciotn(els_VmObj *L, els_CFunction fn, int n);

/*api lib*/
ELS_API void els_lib_init(els_VmObj *l);
ELS_API int els_lib_load(els_VmObj *l);

#endif
